#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
#endregion

namespace MUSA
{
    /// <summary>
    /// The basic terrain. With added senor map features
    /// </summary>
    class Terrain : Object
    {
        //========================================
        //MEMBER VARIABLES
        //========================================
        private BasicEffect basicEffect;

        //Terrain dimensions
        private int width;
        private int length;

        private VertexPositionColor[] terrainVertices;             //Terrain vertices
        private int[,] terrainIndices;                             //Triangle line strip arrays of indexes

        //========================================
        //Constuructors
        //========================================
        
        /// <summary>
        /// Default constructor
        /// </summary>
        public Terrain(Game game)
            : base(game)
        {
            width = 32;
            length = 32;

            createTerrainMap();
        }

        /// <summary>
        /// Primary Constuctor. It is recommended that powers of two are used for the terrain
        /// dimmensions
        /// </summary>
        /// <param name="_w">width parameter</param>
        /// <param name="_l">height parameter</param>
        public Terrain(Game game, int _w, int _l)
            : base(game)
        {
            width = _w + 1;
            length = _l + 1;

            createTerrainMap();
        }

        //========================================
        //MEMBER METHODS
        //========================================

        /// <summary>
        /// Given pre-defined dimensions, fills out the terrainVertices with appropriate points
        /// </summary>
        private void createTerrainMap()
        {
            int arrSize = length * width;                        //determine array size for full

            //create appropriatly sized array to hold vertices
            terrainVertices = new VertexPositionColor[arrSize];      

            //set vertice positions and color
            for (int i = 0; i < arrSize; i++)
            {
                terrainVertices[i].Position = new Vector3(i % width - (width/2), i / width - (width/2), 0);     //set vertice position
                terrainVertices[i].Color = new Color(new Vector3(0.5f, 0.5f, 0.5f));       //set default gray color
            }

            //create triangle strip arrays
            terrainIndices = new int[length - 1, width * 2];

            for (int i = 0; i < length - 1; i++)    //cycle through triangle strip indice
            {
                int k = 0;
                for (int j = 0; j < width * 2 - 1; j += 2)
                {
                    terrainIndices[i, j] = k + (width * i);
                    terrainIndices[i, j + 1] = k + (width * i) + width;
                    k++;
                }
            }
        }

        protected override void Create()
        {
            IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)mGame.Services.GetService(typeof(IGraphicsDeviceService));

            #region Initialize Basic Effects

            //Initialize the Basic Effect
            basicEffect = new BasicEffect(graphicsService.GraphicsDevice, null);

            basicEffect.Alpha = 1.0f;
            basicEffect.DiffuseColor = new Vector3(1.0f, 0.0f, 1.0f);
            basicEffect.SpecularColor = new Vector3(0.25f, 0.25f, 0.25f);
            basicEffect.SpecularPower = 5.0f;
            basicEffect.AmbientLightColor = new Vector3(0.75f, 0.75f, 0.75f);

            basicEffect.DirectionalLight0.Enabled = true;
            basicEffect.DirectionalLight0.DiffuseColor = Vector3.One;
            basicEffect.DirectionalLight0.Direction = Vector3.Normalize(new Vector3(1.0f, -1.0f, -1.0f));
            basicEffect.DirectionalLight0.SpecularColor = Vector3.One;

            basicEffect.DirectionalLight1.Enabled = true;
            basicEffect.DirectionalLight1.DiffuseColor = new Vector3(0.5f, 0.5f, 0.5f);
            basicEffect.DirectionalLight1.Direction = Vector3.Normalize(new Vector3(-1.0f, -1.0f, 1.0f));
            basicEffect.DirectionalLight1.SpecularColor = new Vector3(0.5f, 0.5f, 0.5f);

            basicEffect.LightingEnabled = true;

            basicEffect.View = MUSA.mCamera.View;
            basicEffect.Projection = MUSA.mCamera.Projection;

            //basicEffect.View = Matrix.CreateLookAt(new Vector3(0, 0, 50), Vector3.Zero, Vector3.Up);
            //basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(
            //MathHelper.ToRadians(45),  // 45 degree angle
            //(float)graphicsService.GraphicsDevice.Viewport.Width / (float)graphicsService.GraphicsDevice.Viewport.Height,
            //1.0f, 100.0f);
            //MATRIX//-------

            #endregion Initialize Basic Effects
        }

        public override void Draw(GameTime gTime)
        {
            IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)mGame.Services.GetService(typeof(IGraphicsDeviceService));

            VertexPositionColor[] terrainStrip = new VertexPositionColor[width * 2];

            basicEffect.Begin();
            foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
            {
                pass.Begin();

                for (int i = 0; i < width - 1; i++)
                {
                    for (int j = 0; j < width * 2; j++)
                    {
                        terrainStrip[j] = terrainVertices[terrainIndices[i, j]];
                    }

                    graphicsService.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, terrainStrip, 0, width * 2 - 2);
                }

                pass.End();
            }
            basicEffect.End();
        }

        public override bool Collide(BoundingBox pBox)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public override bool Collide(BoundingSphere pSphere)
        {
            throw new Exception("The method or operation is not implemented.");
        }
    }
}
